#ifndef _CU_UCHAR4_H_
#define _CU_UCHAR4_H_

//**********************************************************************************
// uchar4 operators and functions
//**********************************************************************************
SDH_CALL float4   operator +  (const uchar4 & u, float v) { float4 r = { u.x + v, u.y + v, u.z + v, u.w + v }; return r; }
SDH_CALL float4   operator -  (const uchar4 & u, float v) { float4 r = { u.x - v, u.y - v, u.z - v, u.w - v }; return r; }
SDH_CALL float4   operator *  (const uchar4 & u, float v) { float4 r = { u.x * v, u.y * v, u.z * v, u.w * v }; return r; }
SDH_CALL float4   operator /  (const uchar4 & u, float v) { float4 r = { u.x / v, u.y / v, u.z / v, u.w / v }; return r; }

SDH_CALL float4   operator +  (float v, const uchar4 & u) { float4 r = { v + u.x, v + u.y, v + u.z, v + u.w }; return r; }
SDH_CALL float4   operator -  (float v, const uchar4 & u) { float4 r = { v - u.x, v - u.y, v - u.z, v - u.w }; return r; }
SDH_CALL float4   operator *  (float v, const uchar4 & u) { float4 r = { v * u.x, v * u.y, v * u.z, v * u.w }; return r; }
SDH_CALL float4   operator /  (float v, const uchar4 & u) { float4 r = { v / u.x, v / u.y, v / u.z, v / u.w }; return r; }

SDH_CALL uchar4   operator +  (const uchar4 & u, const uchar4 & v) { uchar4 r = { u.x + v.x, u.y + v.y, u.z + v.z, u.w + v.w }; return r; }
SDH_CALL uchar4   operator -  (const uchar4 & u, const uchar4 & v) { uchar4 r = { u.x - v.x, u.y - v.y, u.z - v.z, u.w - v.w }; return r; }
SDH_CALL uchar4   operator *  (const uchar4 & u, const uchar4 & v) { uchar4 r = { u.x * v.x, u.y * v.y, u.z * v.z, u.w * v.w }; return r; }
SDH_CALL uchar4   operator /  (const uchar4 & u, const uchar4 & v) { uchar4 r = { u.x / v.x, u.y / v.y, u.z / v.z, u.w / v.w }; return r; }

SDH_CALL uchar4 & operator += (uchar4 & u, const uchar4 & v) { u.x += v.x; u.y += v.y; u.z += v.z; u.w += v.w; return u; }
SDH_CALL uchar4 & operator -= (uchar4 & u, const uchar4 & v) { u.x -= v.x; u.y -= v.y; u.z -= v.z; u.w -= v.w; return u; }
SDH_CALL uchar4 & operator *= (uchar4 & u, const uchar4 & v) { u.x *= v.x; u.y *= v.y; u.z *= v.z; u.w *= v.w; return u; }
SDH_CALL uchar4 & operator /= (uchar4 & u, const uchar4 & v) { u.x /= v.x; u.y /= v.y; u.z /= v.z; u.w /= v.w; return u; }

SDH_CALL uchar4 & operator += (uchar4 & u, const float v) { u.x += v; u.y += v; u.z += v; u.w += v; return u; }
SDH_CALL uchar4 & operator -= (uchar4 & u, const float v) { u.x -= v; u.y -= v; u.z -= v; u.w -= v; return u; }
SDH_CALL uchar4 & operator *= (uchar4 & u, const float v) { u.x *= v; u.y *= v; u.z *= v; u.w *= v; return u; }
SDH_CALL uchar4 & operator /= (uchar4 & u, const float v) { u.x /= v; u.y /= v; u.z /= v; u.w /= v; return u; }

SDH_CALL uint  as_uint(uchar4 & ub4) { return *((uint *) &ub4); }

SDH_CALL float  sad (const uchar4 & u, const uchar4 & v) { return (abs(u.x - v.x) + abs(u.y - v.y) + abs(u.z - v.z) + abs(u.w - v.w)); } // Sum of Absolute Differences for xyzw components
SDH_CALL float  ssd (const uchar4 & u, const uchar4 & v) { return (sqr(u.x - v.x) + sqr(u.y - v.y) + sqr(u.z - v.z) + sqr(u.w - v.w)); } // Sum of Squared Differences for xyzw components
SDH_CALL float  sad3(const uchar4 & u, const uchar4 & v) { return (abs(u.x - v.x) + abs(u.y - v.y) + abs(u.z - v.z)); } // Sum of Absolute Differences for xyz components only
SDH_CALL float  ssd3(const uchar4 & u, const uchar4 & v) { return (sqr(u.x - v.x) + sqr(u.y - v.y) + sqr(u.z - v.z)); } // Sum of Squared  Differences for xyz components only

SDH_CALL float4 normalize(const uchar4 & u) { float4 r = {u.x / 255.0f, u.y / 255.0f, u.z / 255.0f, u.w / 255.0f}; return r; }
SDH_CALL float3 normalize3(const uchar4 & u) { float3 r = {u.x / 255.0f, u.y / 255.0f, u.z / 255.0f}; return r; }

SDH_CALL uchar4 uc4(const float3 & v, float w = 0)      { uchar4 r = {v.x, v.y, v.z,   w}; return r; }
SDH_CALL uchar4 uc4(const float4 & v)                   { uchar4 r = {v.x, v.y, v.z, v.w}; return r; }
SDH_CALL uchar4 uc4(uchar x)                            { uchar4 r = {  x,   x,   x,   x}; return r; }
SDH_CALL uchar4 uc4(uchar x, uchar y, uchar z, uchar w) { uchar4 r = {  x,   y,   z,   w}; return r; }
SDH_CALL uchar4 uc4()                                   { uchar4 r = {  0,   0,   0,   0}; return r; }
SDH_CALL uchar4 uc4(const uchar3 & u, uchar w = 0)      { uchar4 r = {u.x, u.y, u.z,   w}; return r; }

#endif